﻿using KinonekoSoftware.CodariaDB.Documents.Keywords;

namespace KinonekoSoftware.Studio.Pages.Galleries
{
    public abstract class _LiteGallery : RepositoryGalleryItem
    {
        protected private readonly RepositoryPropertyManager _PropertyMgr;
        protected private readonly RepositoryRuntime         _runtime;
        protected private readonly InstanceCacheEngine       _engine_cache;
        protected private readonly List<InstanceCache>       _collection;

        private InstanceCache _currentSelected;
        private string        _searchBy;
        private int           _pageBy;
        private SortBy        _sortBy;
        private int           _pageIndex;
        private int           _pageCount;
        private bool          _isQuikEditPanelOpen;

        private int                 _version;
        private List<InstanceCache> _temporaryCollection;


        protected _LiteGallery(InstanceType type)
        {
            _runtime      = Ioc.Get<RepositoryRuntime>();
            _engine_cache = _runtime.GetEngine<InstanceCacheEngine>();
            _PropertyMgr  = _runtime.Repository.PropertyManager;
            _collection   = new List<InstanceCache>(64);
            Type          = type;

            FullyCollection  = new ObservableCollection<InstanceCache>();

            NewInstanceCommand          = CreateCommand(DoNewInstanceCommand);
            LockOrUnlockInstanceCommand = CreateCommand<InstanceCache>(DoLockOrUnlockInstanceCommand);
            QuikEditInstanceCommand     = CreateCommand<InstanceCache>(DoQuikEditInstanceCommand);
            EditInstanceCommand         = CreateCommand<InstanceCache>(DoEditInstanceCommand);
            RemoveInstanceCommand       = CreateCommand<InstanceCache>(DoRemoveInstanceCommand);
            PreviousPageCommand         = CreateCommand(DoPreviousPageCommand);
            NextPageCommand             = CreateCommand(DoNextPageCommand);
        }

        protected virtual void OpenInstance(InstanceCache target) {}


        //-------------------------------------------------------------
        //
        //          Override Methods
        //
        //-------------------------------------------------------------



        #region Override Methods

        protected override async void OnStart()
        {
            Title = LanguageManager.GetEnum(Type);
            using (var session = await Ioc.Get<IBusyServiceEX>().BeginSession("加载数据...."))
            {
                InvalidateDataSource();
                await session.Await();
            }

            base.OnStart();
        }

        protected override async void OnResume()
        {
            Title = LanguageManager.GetEnum(Type);

            if (_version != _engine_cache.Version)
            {
                using (var session = await Ioc.Get<IBusyServiceEX>().BeginSession(""))
                {
                    InvalidateDataSource();
                    await session.Await();
                }
            }

            Title = LanguageManager.GetEnum(Type);
            base.OnResume();
        }

        #endregion

        protected IEnumerable<InstanceCache> BuildOrderedCollection()
        {
            return _sortBy switch
            {
                SortBy.Descending_Name         => _temporaryCollection.OrderByDescending(x => x.Name),
                SortBy.Ascending_CreateTime    => _temporaryCollection.OrderBy(x => x.TimeOfCreated),
                SortBy.Descending_CreateTime   => _temporaryCollection.OrderByDescending(x => x.TimeOfCreated),
                SortBy.Ascending_ModifiedTime  => _temporaryCollection.OrderBy(x => x.TimeOfModified),
                SortBy.Descending_ModifiedTime => _temporaryCollection.OrderByDescending(x => x.TimeOfModified),
                _                              => _temporaryCollection.OrderBy(x => x.Name),
            };
        }

        protected void InvalidatePageInfo()
        {
            //
            // Build OrderedCollection
            FullyCollection.AddMany(BuildOrderedCollection(), true);
        }

        protected void InvalidateDataSource()
        {
            //
            // 获取所有的数据
            _collection.AddMany(_engine_cache.Get(Type), true);
            FullyCollection.Clear();

            //
            // Reset
            _pageIndex = 1;
            _searchBy  = null;

            //
            //
            InvalidatePageSource(1);

            //
            // Raise Updated
            Xplat.RunOnUIThread(() =>
            {
                RaiseUpdated(nameof(PageIndex));
                RaiseUpdated(nameof(SearchBy));
                PushToView();
            });

            //
            // update sync version
            _version = _engine_cache.Version;
        }

        protected void InvalidatePageSource(int index)
        {
            //
            // index 的取值范围[1, 32767]
            index = Math.Clamp(index, 1, short.MaxValue);
            var pageBy = Math.Clamp(_pageBy, 50, 250);
            var mask   = pageBy - 1;
            int pageCount;

            //
            // 设置数据源
            if (string.IsNullOrEmpty(_searchBy))
            {
                //
                // 没有搜索操作时，直接添加源

                //
                // 计算当前集合的页面总数
                pageCount = (_collection.Count + mask) / pageBy;


                if (_collection.Count == 0)
                {
                    //
                    // 避免错误
                    Xplat.RunOnUIThread(() =>
                    {
                        //
                        // 清空集合
                        FullyCollection.Clear();

                        _pageCount = pageCount;
                        _pageIndex = 1;
                        RaiseUpdated(nameof(PageIndex));
                        RaiseUpdated(nameof(PageCount));
                    });

                    return;
                }

                //
                // 获得总数
                //
                // 假设 count = 300, pageIndex = 2, pageBy = 50,
                // Min（50， 250）
                //
                // 假设 count = 300, pageIndex = 5, pageBy = 50,
                // Min（50， 250）
                var skip   = (index - 1) * pageBy;
                var paging = Math.Min(_collection.Count - skip, pageBy);

                //
                //
                var pagingIterator = _collection.Skip(skip)
                                                .Take(paging);

                //
                // 
                _temporaryCollection = pagingIterator.ToList();


            }
            else
            {
                var tempCollection = _collection.Where(x => x.Name.Contains(_searchBy))
                                                .ToList();


                //
                // 计算当前集合的页面总数
                pageCount = (tempCollection.Count + mask) / pageBy;

                if (tempCollection.Count == 0)
                {
                    //
                    // 避免错误
                    Xplat.RunOnUIThread(() =>
                    {
                        //
                        // 清空集合
                        FullyCollection.Clear();

                        _pageCount = pageCount;
                        _pageIndex = 1;
                        RaiseUpdated(nameof(PageIndex));
                        RaiseUpdated(nameof(PageCount));
                    });

                    return;
                }

                //
                // 避免溢出
                if (index >= pageCount)
                {
                    index = 1;
                    Xplat.RunOnUIThread(() =>
                    {
                        _pageIndex = index;
                        RaiseUpdated(nameof(PageIndex));
                    });
                }


                var skip   = (index - 1) * pageBy;
                var paging = Math.Min(tempCollection.Count - skip, pageBy);

                //
                //
                var pagingIterator = tempCollection.Skip(skip)
                                                   .Take(paging);

                //
                // 
                _temporaryCollection = pagingIterator.ToList();
            }

            //
            //
            InvalidatePageInfo();
        }



        #region CommandHandlers

        protected virtual void NewInstanceCommandOverride() {}

        private void DoNewInstanceCommand()
        {
            NewInstanceCommandOverride();

        }

        private void DoEditInstanceCommand(InstanceCache target)
        {
            if (target is null)
            {
                return;
            }

            OpenInstance(target);
        }

        private void DoQuikEditInstanceCommand(InstanceCache target)
        {
            if (target is null)
            {
                return;
            }

            IsQuikEditPanelOpen = true;
        }

        private void DoLockOrUnlockInstanceCommand(InstanceCache target)
        {
            if (target is null)
            {
                return;
            }


            target.IsLocked = !target.IsLocked;
            _engine_cache.UpdateCache(target);
            PushToView();
        }

        private async void DoRemoveInstanceCommand(InstanceCache target)
        {
            if (target is null)
            {
                return;
            }

            if (target.IsLocked)
            {
                await Warning(TitleSR.WarningOperation, TextSR.Remove_Item_Failed_Locked);
                return;
            }

            if (!await RemoveItem())
            {
                return;
            }

            //
            //
            target.IsDeleted = true;

            FullyCollection.Remove(target);
            _collection.Remove(target);
            _engine_cache.RemoveCache(target);
        }

        #endregion



        #region Gallery

        public bool CanPreviousPage() => PageIndex > 1;
        public bool CanNextPage() => PageCount     >= PageIndex + 1;


        private void DoPreviousPageCommand()
        {
            if (!CanPreviousPage())
            {
                return;
            }

            PageIndex -= 1;
            InvalidatePageSource(PageIndex);
            PushToView();
        }

        private void DoNextPageCommand()
        {
            if (!CanNextPage())
            {
                return;
            }

            PageIndex += 1;
            InvalidatePageSource(PageIndex);
            PushToView();
        }

        #endregion


        public bool IsQuikEditPanelOpen
        {
            get => _isQuikEditPanelOpen;
            set => SetValue(ref _isQuikEditPanelOpen, value);
        }

        public int PageIndex
        {
            get => _pageIndex;
            set
            {
                SetValue(ref _pageIndex, Math.Clamp(value, 1, PageCount));
                InvalidatePageSource(value);
            }
        }


        public int PageCount
        {
            get => _pageCount;
            private set => SetValue(ref _pageCount, value);
        }


        public SortBy SortBy
        {
            get => _sortBy;
            set
            {
                SetValue(ref _sortBy, value);
                InvalidatePageSource(PageIndex);
            }
        }


        public int PageBy
        {
            get => _pageBy;
            set
            {
                SetValue(ref _pageBy, value);
                _PropertyMgr.SetPageBy(Type, value);
                InvalidatePageSource(PageIndex);
            }
        }


        public string SearchBy
        {
            get => _searchBy;
            set
            {
                SetValue(ref _searchBy, value);
                InvalidatePageSource(PageIndex);
            }
        }

        public InstanceCache CurrentSelected
        {
            get => _currentSelected;
            set
            {
                SetValue(ref _currentSelected, value);
                PushToView();
            }
        }

        public ObservableCollection<InstanceCache> FullyCollection  { get; }


        public ICommandEX    NewInstanceCommand          { get; }
        public ICommandEX    EditInstanceCommand         { get; }
        public ICommandEX    QuikEditInstanceCommand     { get; }
        public ICommandEX    LockOrUnlockInstanceCommand { get; }
        public ICommandEX    RemoveInstanceCommand       { get; }
        public ICommandEX    NextPageCommand             { get; }
        public ICommandEX    PreviousPageCommand         { get; }
        public InstanceType Type                        { get; internal set; }
    }
}